package market

import (
	"deeptrain/auth"
	"deeptrain/utils"
	"log"
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"
)

type MarketingPreferenceForm struct {
	EmailMarketing bool `json:"email_marketing"`
}

type TestEmailForm struct {
	Subject   string `json:"subject" binding:"required"`
	Content   string `json:"content" binding:"required"`
	TestEmail string `json:"test_email" binding:"required"`
}

func RequireAuthByCtx(c *gin.Context) *auth.User {
	user := c.MustGet("user").(string)
	if user == "" {
		c.JSON(http.StatusOK, gin.H{
			"status": false,
			"error":  "authentication failed",
		})
		return nil
	}
	return &auth.User{Username: user}
}

func RequireAdminByCtx(c *gin.Context) *auth.User {
	user := RequireAuthByCtx(c)
	if user == nil {
		return nil
	}

	db := utils.GetDBFromContext(c)
	if !auth.IsUserAdmin(db, user.Username) {
		c.JSON(http.StatusOK, gin.H{
			"status": false,
			"error":  "admin access required",
		})
		return nil
	}
	return user
}

func SendMarketingEmailView(c *gin.Context) {
	var form MarketingEmailRequest
	if err := c.ShouldBindJSON(&form); err != nil {
		c.JSON(http.StatusOK, gin.H{
			"status": false,
			"error":  err.Error(),
		})
		return
	}

	admin := RequireAdminByCtx(c)
	if admin == nil {
		return
	}

	db := utils.GetDBFromContext(c)
	admin.Use(db)

	users, err := GetUsersForMarketing(db)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"status": false,
			"error":  "failed to get users for marketing",
		})
		return
	}

	if len(users) == 0 {
		c.JSON(http.StatusOK, gin.H{
			"status": false,
			"error":  "no users opted in for marketing emails",
		})
		return
	}

	emailID, err := LogMarketingEmail(db, form.Subject, form.Content, admin.ID)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"status": false,
			"error":  "failed to log marketing email",
		})
		return
	}

	var totalSent, successfulSent, failedSent int
	for _, user := range users {
		totalSent++
		err := SendMarketingMailWithName(user.Email, form.Subject, form.Content, user.DisplayName)
		if err != nil {
			failedSent++
			log.Printf("Failed to send marketing email to %s: %v", user.Email, err)
			LogMarketingEmailRecipient(db, emailID, user.ID, user.Email, "failed", err.Error())
		} else {
			successfulSent++
			LogMarketingEmailRecipient(db, emailID, user.ID, user.Email, "sent", "")
		}
	}

	err = UpdateMarketingEmailStats(db, emailID, totalSent, successfulSent, failedSent)
	if err != nil {
		log.Printf("Failed to update marketing email stats: %v", err)
	}

	c.JSON(http.StatusOK, gin.H{
		"status":  true,
		"message": "Marketing email sent successfully",
		"statistics": gin.H{
			"total_sent":      totalSent,
			"successful_sent": successfulSent,
			"failed_sent":     failedSent,
		},
	})
}

func SendTestMarketingEmailView(c *gin.Context) {
	var form TestEmailForm
	if err := c.ShouldBindJSON(&form); err != nil {
		c.JSON(http.StatusOK, gin.H{
			"status": false,
			"error":  err.Error(),
		})
		return
	}

	admin := RequireAdminByCtx(c)
	if admin == nil {
		return
	}

	// Validate email format
	if !strings.Contains(form.TestEmail, "@") {
		c.JSON(http.StatusOK, gin.H{
			"status": false,
			"error":  "invalid email format",
		})
		return
	}

	// Send test email
	err := SendMarketingMailWithName(form.TestEmail, "[TEST] "+form.Subject, form.Content, "测试用户")
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"status": false,
			"error":  "failed to send test email: " + err.Error(),
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"status":  true,
		"message": "Test email sent successfully",
	})
}

// GetMarketingPreferenceView handles getting user's marketing preferences
func GetMarketingPreferenceView(c *gin.Context) {
	user := RequireAuthByCtx(c)
	if user == nil {
		return
	}

	db := utils.GetDBFromContext(c)
	userID := user.GetID(db)

	preference, err := GetMarketingPreference(db, userID)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"status": false,
			"error":  "failed to get marketing preference",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"status":          true,
		"email_marketing": preference.EmailMarketing,
	})
}

func SetMarketingPreferenceView(c *gin.Context) {
	var form MarketingPreferenceForm
	if err := c.ShouldBindJSON(&form); err != nil {
		c.JSON(http.StatusOK, gin.H{
			"status": false,
			"error":  err.Error(),
		})
		return
	}

	user := RequireAuthByCtx(c)
	if user == nil {
		return
	}

	db := utils.GetDBFromContext(c)
	userID := user.GetID(db)

	err := SetMarketingPreference(db, userID, form.EmailMarketing)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"status": false,
			"error":  "failed to set marketing preference",
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"status":  true,
		"message": "Marketing preference updated successfully",
	})
}

func GetMarketingEmailLogsView(c *gin.Context) {
	admin := RequireAdminByCtx(c)
	if admin == nil {
		return
	}

	page := utils.ParseInt(c.Query("page"), 1) - 1
	pageSize := 10

	db := utils.GetDBFromContext(c)

	var total int
	err := db.QueryRow(`SELECT COUNT(*) FROM marketing_email_log`).Scan(&total)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"status": false,
			"error":  err.Error(),
		})
		return
	}

	totalPage := total / pageSize
	if total%pageSize != 0 {
		totalPage++
	}

	if page >= totalPage {
		page = totalPage - 1
	} else if page < 0 {
		page = 0
	}

	logs := make([]gin.H, 0)
	rows, err := db.Query(`
		SELECT mel.id, mel.subject, mel.content, mel.sender_id, mel.total_sent, 
		       mel.successful_sent, mel.failed_sent, mel.created_at, a.username
		FROM marketing_email_log mel
		JOIN auth a ON mel.sender_id = a.id
		ORDER BY mel.created_at DESC
		LIMIT ? OFFSET ?
	`, pageSize, page*pageSize)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"status": false,
			"error":  err.Error(),
		})
		return
	}
	defer rows.Close()

	for rows.Next() {
		var (
			id             int
			subject        string
			content        string
			senderID       int
			totalSent      int
			successfulSent int
			failedSent     int
			createdAt      []uint8
			senderName     string
		)
		err := rows.Scan(&id, &subject, &content, &senderID, &totalSent, &successfulSent, &failedSent, &createdAt, &senderName)
		if err != nil {
			c.JSON(http.StatusOK, gin.H{
				"status": false,
				"error":  err.Error(),
			})
			return
		}

		logs = append(logs, gin.H{
			"id":              id,
			"subject":         subject,
			"content":         content,
			"sender_id":       senderID,
			"sender_name":     senderName,
			"total_sent":      totalSent,
			"successful_sent": successfulSent,
			"failed_sent":     failedSent,
			"created_at":      utils.ConvertTime(createdAt).Format("2006-01-02 15:04:05"),
		})
	}

	c.JSON(http.StatusOK, gin.H{
		"status": true,
		"data":   logs,
		"total":  totalPage,
	})
}

func GetMarketingStatsView(c *gin.Context) {
	admin := RequireAdminByCtx(c)
	if admin == nil {
		return
	}

	db := utils.GetDBFromContext(c)

	var optedInUsers, totalUsers int
	err := db.QueryRow(`SELECT COUNT(*) FROM auth WHERE active = TRUE`).Scan(&totalUsers)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"status": false,
			"error":  err.Error(),
		})
		return
	}

	err = db.QueryRow(`
		SELECT COUNT(*) FROM auth a 
		LEFT JOIN marketing_preferences mp ON a.id = mp.user_id
		WHERE a.active = TRUE AND (mp.email_marketing = TRUE OR mp.email_marketing IS NULL)
	`).Scan(&optedInUsers)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"status": false,
			"error":  err.Error(),
		})
		return
	}

	var totalEmailsSent, totalEmailsDelivered, totalEmailsFailed int
	err = db.QueryRow(`
		SELECT 
			COALESCE(SUM(total_sent), 0),
			COALESCE(SUM(successful_sent), 0),
			COALESCE(SUM(failed_sent), 0)
		FROM marketing_email_log
	`).Scan(&totalEmailsSent, &totalEmailsDelivered, &totalEmailsFailed)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"status": false,
			"error":  err.Error(),
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"status": true,
		"statistics": gin.H{
			"total_users":            totalUsers,
			"opted_in_users":         optedInUsers,
			"total_emails_sent":      totalEmailsSent,
			"total_emails_delivered": totalEmailsDelivered,
			"total_emails_failed":    totalEmailsFailed,
		},
	})
}
